﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SQLite;

namespace PersonalAccounting.DataAccess
{
    public class DAOMovimiento : IDAO<MovimientoVO>
    {

        #region IDAO<MovimientoVO> Members

        public bool Select(MovimientoVO obj)
        {
            SQLiteCommand cmd = new SQLiteCommand();
            SQLiteParameter codigo;
            SQLiteDataReader reader;

            cmd.Connection = SQLiteConn.GetInstance().Connection;
            cmd.CommandText = QuerySelect();

            codigo = new SQLiteParameter("@codigo", obj.Codigo);

            cmd.Parameters.Add(codigo);

            reader = cmd.ExecuteReader();

            if (reader.Read())
            {
                Load(obj, reader);
                return true;
            }
            else
                return false;
        }

        public void Load(MovimientoVO obj, SQLiteDataReader reader)
        {
            obj.Codigo = Convert.ToInt32(reader["MovCodigo"]);
            obj.Fecha = Convert.ToDateTime(reader["MovFecha"]);
            obj.Tipo = Convert.ToString(reader["MovTipo"]);
            obj.Descripcion = Convert.ToString(reader["MovDescripcion"]);
            obj.Importe = Convert.ToDouble(reader["MovImporte"]);

            IDAO<CuentaVO> dao = new DAOCuenta();
            dao.Load(obj.Cuenta, reader);
        }


        public bool Insert(MovimientoVO obj)
        {
            SQLiteCommand cmd = new SQLiteCommand();
            SQLiteParameter codigo, cuenta, fecha, tipo, descripcion, importe;
            int records;

            cmd.Connection = SQLiteConn.GetInstance().Connection;
            cmd.CommandText = QueryInsert();

            codigo = new SQLiteParameter("@codigo", obj.Codigo);
            cuenta = new SQLiteParameter("@cuenta", obj.Cuenta.Codigo);
            fecha = new SQLiteParameter("@fecha", obj.Fecha);
            tipo = new SQLiteParameter("@tipo", obj.Tipo);
            descripcion = new SQLiteParameter("@descripcion", obj.Descripcion);
            importe = new SQLiteParameter("@importe", obj.Importe);

            cmd.Parameters.Add(codigo);
            cmd.Parameters.Add(cuenta);
            cmd.Parameters.Add(fecha);
            cmd.Parameters.Add(tipo);
            cmd.Parameters.Add(descripcion);
            cmd.Parameters.Add(importe);

            records = cmd.ExecuteNonQuery();

            return (records > 0);
        }

        public bool Update(MovimientoVO obj)
        {
            SQLiteCommand cmd = new SQLiteCommand();
            SQLiteParameter codigo, cuenta, fecha, tipo, descripcion, importe;
            int records;

            cmd.Connection = SQLiteConn.GetInstance().Connection;
            cmd.CommandText = QueryUpdate();

            cuenta = new SQLiteParameter("@cuenta", obj.Cuenta.Codigo);
            fecha = new SQLiteParameter("@fecha", obj.Fecha);
            tipo = new SQLiteParameter("@tipo", obj.Tipo);
            descripcion = new SQLiteParameter("@descripcion", obj.Descripcion);
            importe = new SQLiteParameter("@importe", obj.Importe);
            codigo = new SQLiteParameter("@codigo", obj.Codigo);
            
            cmd.Parameters.Add(cuenta);
            cmd.Parameters.Add(fecha);
            cmd.Parameters.Add(tipo);
            cmd.Parameters.Add(descripcion);
            cmd.Parameters.Add(importe);
            cmd.Parameters.Add(codigo);

            records = cmd.ExecuteNonQuery();

            return (records > 0);
        }

        public bool Delete(MovimientoVO obj)
        {
            SQLiteCommand cmd = new SQLiteCommand();
            SQLiteParameter codigo;
            int records;

            cmd.Connection = SQLiteConn.GetInstance().Connection;
            cmd.CommandText = QueryDelete();

            codigo = new SQLiteParameter("@codigo", obj.Codigo);

            cmd.Parameters.Add(codigo);

            records = cmd.ExecuteNonQuery();

            return (records > 0);
        }


        public List<MovimientoVO> GetAll()
        {
            SQLiteCommand cmd = new SQLiteCommand();
            SQLiteDataReader reader = null;
            List<MovimientoVO> lista = new List<MovimientoVO>();
            MovimientoVO movimiento = null;

            cmd.Connection = SQLiteConn.GetInstance().Connection;
            cmd.CommandText = QueryGetAll();

            reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                movimiento = new MovimientoVO();
                Load(movimiento, reader);
                lista.Add(movimiento);
            }

            return lista;
        }

        #endregion

        #region Public Methods

        public int GetNextCode()
        {
            SQLiteCommand cmd = new SQLiteCommand();
            SQLiteDataReader reader = null;
            int nextCode = 1;

            cmd.Connection = SQLiteConn.GetInstance().Connection;
            cmd.CommandText = QueryNextCode();

            reader = cmd.ExecuteReader();

            if (reader.Read())
                nextCode = Convert.ToInt32(reader["MovCodigo"]);

            return nextCode;
        }

        public List<string> GetListTipo(CuentaVO cuenta)
        {
            SQLiteCommand cmd = new SQLiteCommand();
            SQLiteParameter codCuenta = null;
            SQLiteDataReader reader = null;
            List<string> lista = new List<string>();

            cmd.Connection = SQLiteConn.GetInstance().Connection;
            cmd.CommandText = QueryListTipo();

            codCuenta = new SQLiteParameter("@cuenta", cuenta.Codigo);
            cmd.Parameters.Add(codCuenta);

            reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                string tipo = Convert.ToString(reader["Tipo"]);
                lista.Add(tipo);
            }

            reader.Close();
            return lista;
        }

        public double GetSaldoInicial(DateTime fecha, CuentaVO cuenta)
        {
            SQLiteCommand cmd = new SQLiteCommand();
            SQLiteParameter parCuenta = null, parFecha = null;
            SQLiteDataReader reader = null;
            double saldoInicial = 0;

            cmd.Connection = SQLiteConn.GetInstance().Connection;
            cmd.CommandText = QuerySaldoInicial();
            
            parCuenta = new SQLiteParameter("@cuenta", cuenta.Codigo);
            parFecha = new SQLiteParameter("@fecha", fecha);

            cmd.Parameters.Add(parCuenta);
            cmd.Parameters.Add(parFecha);

            reader = cmd.ExecuteReader();

            if (reader.Read())
            {
                if (!Convert.IsDBNull(reader["SdoInicial"]))
                    saldoInicial = Convert.ToDouble(reader["SdoInicial"]);
            }

            reader.Close();
            return saldoInicial;
        }

        public List<MovimientoVO> GetMovtosPeriodo(DateTime desde, DateTime hasta, CuentaVO cuenta)
        {
            SQLiteCommand cmd = new SQLiteCommand();
            SQLiteParameter parCuenta = null, parFechaDesde = null, parFechaHasta = null;
            SQLiteDataReader reader = null;
            List<MovimientoVO> lista = new List<MovimientoVO>();

            cmd.Connection = SQLiteConn.GetInstance().Connection;
            cmd.CommandText = QueryMovtosPeriodo();

            parCuenta = new SQLiteParameter("@cuenta", cuenta.Codigo);
            parFechaDesde = new SQLiteParameter("@fechaDesde", desde);
            parFechaHasta = new SQLiteParameter("@fechaHasta", hasta);

            cmd.Parameters.Add(parCuenta);
            cmd.Parameters.Add(parFechaDesde);
            cmd.Parameters.Add(parFechaHasta);

            reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                MovimientoVO mov = new MovimientoVO();
                Load(mov, reader);
                lista.Add(mov);
            }

            reader.Close();
            return lista;
        }

        #endregion


        #region SQL

        private string QuerySelect()
        {
            return "SELECT " + Campos() +
                   "FROM Movtos " +
                   "JOIN Ctas ON (Movtos.IdCta = Ctas.IdCta) " +
                   "JOIN Monedas ON (Ctas.IdMoneda = Monedas.IdMoneda) " +
                   "WHERE IdMov = @codigo";
        }

        private string QueryGetAll()
        {
            return "SELECT " + Campos() +
                   "FROM Movtos " +
                   "JOIN Ctas ON (Movtos.IdCta = Ctas.IdCta) " +
                   "JOIN Monedas ON (Ctas.IdMoneda = Monedas.IdMoneda) " +
                   "ORDER BY IdMov";
        }

        private string QueryNextCode()
        {
            return "SELECT Max(IdMov) + 1 AS MovCodigo " +
                   "FROM Movtos";
        }

        private string QueryListTipo()
        {
            return "SELECT DISTINCT Tipo " +
                   "FROM Movtos " +
                   "WHERE IdCta = @cuenta";
        }

        private string QuerySaldoInicial()
        {
            return "SELECT " + CmpSaldoInicial() +
                   "FROM Movtos " +
                   "WHERE Movtos.IdCta = @cuenta " +
                    " AND Movtos.Fecha < @fecha";
        }

        private string QueryMovtosPeriodo()
        {
            return "SELECT " + Campos() +
                   "FROM Movtos " +
                   "JOIN Ctas ON (Movtos.IdCta = Ctas.IdCta) " +
                   "JOIN Monedas ON (Ctas.IdMoneda = Monedas.IdMoneda) " +
                   "WHERE Movtos.IdCta = @cuenta " +
                    " AND Movtos.Fecha BETWEEN @fechaDesde AND @fechaHasta " +
                   "ORDER BY Movtos.Fecha";
        }
        
        
        public string Campos()
        {
            DAOCuenta dao = new DAOCuenta();
            return " Movtos.IdMov AS MovCodigo," +
                   " Movtos.Fecha AS MovFecha," +
                   " Movtos.Tipo AS MovTipo," +
                   " Movtos.Descrip AS MovDescripcion," +
                   " Movtos.Importe AS MovImporte," +
                   dao.Campos();
        }

        public string CmpSaldoInicial()
        {
            return " Sum(Movtos.Importe) AS SdoInicial ";
        }
        

        private string QueryInsert()
        {
            return "INSERT INTO Movtos " +
                        "(IdMov, IdCta, Fecha, Tipo, Descrip, Importe) " +
                   "VALUES " +
                        "(@codigo, @cuenta, @fecha, @tipo, @descripcion, @importe)";
        }

        private string QueryUpdate()
        {
            return "UPDATE Movtos SET " +
                        "IdCta = @cuenta, " +
                        "Fecha = @fecha, " +
                        "Tipo = @tipo, " +
                        "Descrip = @descripcion, " + 
                        "Importe = @importe " +
                   "WHERE IdMov = @codigo";
        }

        private string QueryDelete()
        {
            return "DELETE FROM Movtos WHERE IdMov = @codigo";
        }

        #endregion

    }
}